package com.maple.common.widget

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.annotation.ColorInt
import androidx.core.content.withStyledAttributes
import com.maple.common.R
import com.maple.common.log.LogUtil
import com.maple.common.ext.dpToPx
import kotlin.math.roundToInt


/**
 *
 * Tip: zoom ruler
 * Create by SeVen on 2023/11/17 10:07
 */
class ZoomSeekBar @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    /**
     * ruler count default 20,not modifiable
     */
    private var mRulerCount = 20

    /**
     * progress bg color default
     */
    @ColorInt
    private var rulerBgColor = Color.WHITE

    /**
     * ruler color default
     */
    @ColorInt
    private var scalesColor = Color.BLACK

    /**
     * slider color default
     */
    @ColorInt
    private var sliderColor = Color.BLACK

    /**
     * slider size default 5dp
     * sliderHeight max 10dp
     */
    private var sliderHeight = dpToPx(context,5)

    /**
     * record move distance,default 0
     */
    private var mMoveDistance = 0f

    /**
     * record ACTION_DOWN Y,default 0
     */
    private var downY = 0f

    /**
     * slider default position,default height
     */
    private var sliderPositionHeight = 0f

    /**
     * seekbar progress
     */
    private var progress = 0

    /**
     * zoom paint
     */
    private var mPaint: Paint? = null

    /**
     * ZoomSeekBar listener
     */
    private var onSeekBarChangeListener: OnSeekBarChangeListener? = null


    init {
        initAttrs(context, attrs)
        mPaint = Paint()
        mPaint?.isAntiAlias = true
        mPaint?.style = Paint.Style.FILL
        setBackgroundColor(Color.TRANSPARENT)
    }

    /**
     * init attrs
     */
    private fun initAttrs(context: Context, attrs: AttributeSet?) {
        context.withStyledAttributes(attrs, R.styleable.ZoomSeekBar) {
            also {
                apply {
                    rulerBgColor =
                        it.getColor(R.styleable.ZoomSeekBar_zoom_rulerBgColor, rulerBgColor)
                    scalesColor = it.getColor(R.styleable.ZoomSeekBar_zoom_scalesColor, scalesColor)
                    sliderColor = it.getColor(R.styleable.ZoomSeekBar_zoom_sliderColor, sliderColor)
                    sliderHeight =
                        it.getInt(R.styleable.ZoomSeekBar_zoom_sliderHeight, sliderHeight)
                    progress = it.getInt(R.styleable.ZoomSeekBar_zoom_progress, progress)
                }
            }
        }

        if (progress < 0) {
            throw Exception("setProgress method value error,can not Less then 0!")
        }
        if (progress > 100) {
            throw Exception("setProgress method value error,can not exceed then 100!")
        }
        if (sliderHeight > dpToPx(context, 10f)) {
            throw Exception("sliderHeight  value error,can not exceed then 10!")
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(measuredWidth(widthMeasureSpec), measuredHeight(heightMeasureSpec))
    }

    private fun getMeasureSpaceInfo(measureSpec: Int): Pair<Int, Int> {
        //测量模式，从xml获取
        val specMode = MeasureSpec.getMode(measureSpec)
        //测量大小，从xml获取
        val specSize = MeasureSpec.getSize(measureSpec)
        return Pair(specMode, specSize)
    }

    private fun measureSize(specMode: Int, specSize: Int, defaultSpecSize: Int): Int {
        return if (specMode == MeasureSpec.EXACTLY) specSize else {
            if (specMode == MeasureSpec.AT_MOST) {
                defaultSpecSize.coerceAtMost(specSize)
            } else defaultSpecSize
        }
    }

    private fun measuredWidth(widthMeasureSpec: Int): Int {
        val (specMode, specSize) = getMeasureSpaceInfo(widthMeasureSpec)
        val defaultSpecSize = dpToPx(context, 24)
        LogUtil.d(tag = "ZoomSeekBar", message = "defaultSpecSize_width = $defaultSpecSize")
        return measureSize(specMode, specSize, defaultSpecSize)
    }

    private fun measuredHeight(heightMeasureSpec: Int): Int {
        val (specMode, specSize) = getMeasureSpaceInfo(heightMeasureSpec)
        val defaultSpecSize = dpToPx(context, 100) + sliderHeight
        //
        sliderPositionHeight = (defaultSpecSize) * (1 - progress / 100f)
        LogUtil.d(tag = "ZoomSeekBar", message = "defaultSpecSize_height = $defaultSpecSize")
        LogUtil.d(tag = "ZoomSeekBar", message = "sliderPositionHeight = $sliderPositionHeight")
        return measureSize(specMode, specSize, defaultSpecSize)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        onDrawRulerBackground(canvas)
        onDrawRulerScales(canvas)
        onDrawSlider(canvas)
    }

    /**
     *  draw ruler background
     */
    private fun onDrawRulerBackground(canvas: Canvas?) {
        mPaint?.let {
            it.color = rulerBgColor
            val startX = 0f
            val startY = 0f
            val stopX = width.toFloat()
            val stopY = height.toFloat()
            val rulerRectF = RectF(startX, startY, stopX, stopY)
            canvas?.drawRect(rulerRectF, it)
        }
    }

    /**
     * draw ruler, 20 scales in total,10 large  scales and 10  small scales
     */
    private fun onDrawRulerScales(canvas: Canvas?) {
        mPaint?.let {
            it.color = scalesColor
            (1 until mRulerCount).forEach { index ->
                val y = (height / mRulerCount * index).toFloat()
                val leftStartX = 0f
                val rightStartX = width.toFloat()
                if (index % 2 == 0) {
                    // left line
                    val leftStopX = leftStartX + 12
                    canvas?.drawLine(leftStartX, y, leftStopX, y, it)
                    //right line
                    val rightStopX = rightStartX - 12
                    canvas?.drawLine(rightStartX, y, rightStopX, y, it)
                } else {
                    val leftStopX = leftStartX + 6
                    //left line
                    canvas?.drawLine(leftStartX, y, leftStopX, y, it)
                    val rightStopX = rightStartX - 6
                    // right line
                    canvas?.drawLine(rightStartX, y, rightStopX, y, it)
                }
            }
        }
    }

    /**
     * draw slider
     */
    private fun onDrawSlider(canvas: Canvas?) {
        mPaint?.let {
            it.color = sliderColor
            //slider init position
            val startX = 0f
            sliderPositionHeight -= mMoveDistance
            //boundary treatment
            if ((sliderPositionHeight - sliderHeight) < 0) {
                sliderPositionHeight = sliderHeight.toFloat()
            }
            if (sliderPositionHeight > height) {
                sliderPositionHeight = height.toFloat()
            }
            progress = ((1 - sliderPositionHeight / height) * 100).roundToInt()
            LogUtil.d("default progress $progress", tag = "ZoomSeekBar")
            onSeekBarChangeListener?.onProgressChanged(this@ZoomSeekBar, progress)
            LogUtil.d(
                message = "sliderPositionHeight =$sliderPositionHeight height = $height",
                tag = "ZoomSeekBar"
            )
            val stopX = width.toFloat()
            val stopY = sliderPositionHeight - sliderHeight
            val sliderRectF = RectF(startX, sliderPositionHeight, stopX, stopY)
            canvas?.drawRect(sliderRectF, it)
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {
                downY = event.y
            }

            MotionEvent.ACTION_MOVE -> {
                mMoveDistance = downY - event.y
                invalidate()
                LogUtil.d(
                    tag = "ZoomSeekBar",
                    message = "event.x = ${event.x} ,event.y = ${event.y}"
                )
                LogUtil.d(tag = "ZoomSeekBar", message = "default distance = $mMoveDistance")
                downY = event.y
            }

            MotionEvent.ACTION_UP -> {

            }
        }
        return true
    }

    /**
     * set progress,update sliderPositionHeight
     */
    fun setProgress(progress: Int) {
        LogUtil.d("progress#$progress", tag = "ZoomSeekBar")
        if (progress < 0) {
            throw Exception("setProgress method value error,can not Less then 0!")
        }
        if (progress > 100) {
            throw Exception("setProgress method value error,can not exceed then 100!")
        }
        if (this.progress != progress) {
            this.progress = progress
            invalidate()
        }
    }

    interface OnSeekBarChangeListener {
        fun onProgressChanged(zoomSeekBar: ZoomSeekBar, progress: Int)
    }

    fun setOnSeekBarChangeListener(onSeekBarChangeListener: OnSeekBarChangeListener) = apply {
        this.onSeekBarChangeListener = onSeekBarChangeListener
    }

    /**
     * get progress
     */
    fun getProgress(): Int = this.progress

    private fun build(builder: Builder) {
        rulerBgColor = builder.rulerBgColor ?: rulerBgColor
        scalesColor = builder.scalesColor ?: scalesColor
        sliderColor = builder.sliderColor ?: sliderColor
        sliderHeight = builder.sliderHeight ?: sliderHeight
        progress = builder.progress ?: progress
        onSeekBarChangeListener = builder.onSeekBarChangeListener
        this.invalidate()
    }

    inner class Builder {
        /**
         * progress bg color default
         */
        @ColorInt
        var rulerBgColor: Int? = null
            private set

        /**
         * ruler color default
         */
        @ColorInt
        var scalesColor: Int? = null
            private set

        /**
         * slider color default
         */
        @ColorInt
        var sliderColor: Int? = null
            private set

        /**
         * slider size default 5dp
         */
        var sliderHeight: Int? = null
            private set

        /**
         * seekbar progress
         */
        var progress: Int? = null
            private set

        var onSeekBarChangeListener: OnSeekBarChangeListener? = null

        fun setRulerBgColor(@ColorInt rulerBgColor: Int) = apply {
            this.rulerBgColor = rulerBgColor
        }

        fun setScalesColor(@ColorInt scalesColor: Int) = apply {
            this.scalesColor = scalesColor
        }

        fun setSliderColor(@ColorInt sliderColor: Int) = apply {
            this.sliderColor = sliderColor
        }

        fun setSliderHeight(sliderHeight: Int) = apply {
            this.sliderHeight = sliderHeight
        }

        fun setProgress(progress: Int) = apply {
            this.progress = progress
        }

        fun setOnSeekBarChangeListener(onSeekBarChangeListener: OnSeekBarChangeListener) = apply {
            this.onSeekBarChangeListener = onSeekBarChangeListener
        }

        fun build() {
            this@ZoomSeekBar.build(this)
        }
    }
}